package main;

import java.util.Enumeration;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.Logger;

import terrain.TerrainMap;
import test.BaseAppSettings;
import test.OwnCamera;

import com.jme3.app.Application;
import com.jme3.app.StatsView;
import com.jme3.collision.CollisionResult;
import com.jme3.collision.CollisionResults;
import com.jme3.font.BitmapFont;
import com.jme3.font.BitmapText;
import com.jme3.input.InputManager;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Quaternion;
import com.jme3.math.Ray;
import com.jme3.math.Vector3f;
import com.jme3.niftygui.NiftyJmeDisplay;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.queue.RenderQueue.Bucket;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial.CullHint;
import com.jme3.system.JmeContext.Type;
import com.jme3.util.BufferUtils;

import de.lessvoid.nifty.Nifty;

public class MainApp extends Application {

	private static OwnCamera ownCam;

	private static Node rootNode = new Node("Root Node");
	private static Node gameNode = new Node("Main Game Node");
	private static Node guiNode = new Node("Gui Node");
	private static Node guiHUDNode = new Node("Gui HUD Node");
	private static Node guiIGNode = new Node("Gui IG Node");
	private static Nifty mainGuiNifty;
	private static Nifty igGuiNifty;
	public static InputManager inMa;
	
	private Node shootables;
	
	private float secondCounter = 0.0f;
	private BitmapText fpsText;
	private BitmapFont guiFont;
	private StatsView statsView;
	
	private static NiftyJmeDisplay igGuiDisplay;
	private static boolean igGuiOpen = false;
	
	private AppActionListener actionListener = new AppActionListener();
	
	private static TerrainMap terrainMap;
	
	public MainApp() {
		super();
		Enumeration<String> en = LogManager.getLogManager().getLoggerNames();
		while (en.hasMoreElements()) {
			Logger.getLogger(en.nextElement()).setLevel(Level.WARNING);
		}
	}

	public static void main(String[] args) {
		MainApp app = new MainApp();
		app.start();
	}

	private class AppActionListener implements ActionListener {
		public void onAction(String name, boolean value, float tpf) {
			if (!value)
				return;

			if (name.equals("SIMPLEAPP_Exit")) {
				stop();
			} else if (name.equals("SIMPLEAPP_CameraPos")) {
				if (cam != null) {
					Vector3f loc = cam.getLocation();
					Quaternion rot = cam.getRotation();
					System.out.println("Camera Position: (" + loc.x + ", "
							+ loc.y + ", " + loc.z + ")");
					System.out.println("Camera Rotation: " + rot);
					System.out.println("Camera Direction: "
							+ cam.getDirection());
				}
			} else if (name.equals("SIMPLEAPP_Memory")) {
				BufferUtils.printCurrentDirectMemory(null);
			} else if (name.equals("SIMPLEAPP_Menu")) {
				if (igGuiOpen) {
					igGuiNifty.exit();
					ownCam.setEnabled(true);
					igGuiOpen = false;
				} else {
					igGuiDisplay = new NiftyJmeDisplay(assetManager, inputManager, audioRenderer, guiViewPort);
					igGuiNifty = igGuiDisplay.getNifty();
					igGuiNifty.fromXml("interface/IGGui.xml", "start");
					guiViewPort.addProcessor(igGuiDisplay);
					ownCam.setEnabled(false);
					igGuiOpen = true;
				}
			} else if (name.equals("clickRight")) {
				Vector3f origin    = cam.getWorldCoordinates(inputManager.getCursorPosition(), 0.0f);
				Vector3f direction = cam.getWorldCoordinates(inputManager.getCursorPosition(), 0.3f);
				direction.subtractLocal(origin).normalizeLocal();

				Ray ray = new Ray(origin, direction);
				CollisionResults results = new CollisionResults();
				shootables.collideWith(ray, results);
				if (results.size() > 0) {
					CollisionResult closest = results.getClosestCollision();
					Geometry geo = closest.getGeometry();
					Vector3f vec = geo.getLocalTranslation();
					if (vec.z == 2) {
						if (closest.getGeometry().getName().equals("Earth")) {
							terrainMap.removeTile((int)vec.x, (int)vec.y);
						}
					}
				}
			}
		}
	}

	@Override
	public void start() {

		settings = BaseAppSettings.loadBaseSettings();

		super.start();
	}

	public OwnCamera getOwnCamera() {
		return ownCam;
	}

	public Node getGuiNode() {
		return guiNode;
	}

	public Node getRootNode() {
		return rootNode;
	}
	
	public void loadFPSText() {
		guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
		fpsText = new BitmapText(guiFont, false);
		fpsText.setLocalTranslation(0, fpsText.getLineHeight(), 0);
		fpsText.setText("Frames per second");
		guiNode.attachChild(fpsText);
	}

	public void loadStatsView() {
		statsView = new StatsView("Statistics View", assetManager,
				renderer.getStatistics());
		// move it up so it appears above fps text
		statsView.setLocalTranslation(0, fpsText.getLineHeight(), 0);
		guiNode.attachChild(statsView);
	}

	@Override
	public void initialize() {
		super.initialize();

		guiNode.setQueueBucket(Bucket.Gui);
		guiNode.setCullHint(CullHint.Never);
		loadFPSText();
		loadStatsView();
		viewPort.attachScene(rootNode);
		guiViewPort.attachScene(guiNode);

		if (inputManager != null) {
			ownCam = new OwnCamera(cam);
			ownCam.registerWithInput(inputManager);

			if (context.getType() == Type.Display)
				inputManager.addMapping("SIMPLEAPP_Exit", new KeyTrigger(
						KeyInput.KEY_ESCAPE));
			inputManager.addMapping("SIMPLEAPP_Menu", new KeyTrigger(
					KeyInput.KEY_F1));
			
			inputManager.addMapping("SIMPLEAPP_CameraPos", new KeyTrigger(
					KeyInput.KEY_C));
			inputManager.addMapping("SIMPLEAPP_Memory", new KeyTrigger(
					KeyInput.KEY_M));
			inputManager.addMapping("clickRight",
				      new MouseButtonTrigger(MouseInput.BUTTON_RIGHT));
			
			inputManager.addListener(actionListener, "SIMPLEAPP_Exit",
					"SIMPLEAPP_CameraPos", "SIMPLEAPP_Memory", "SIMPLEAPP_Menu", "clickRight");
		}

		simpleInitApp();
	}

	@Override
	public void update() {
		if (speed == 0 || paused)
			return;

		super.update();
		float tpf = timer.getTimePerFrame() * speed;

		secondCounter += timer.getTimePerFrame();
		int fps = (int) timer.getFrameRate();
		if (secondCounter >= 1.0f) {
			fpsText.setText("Frames per second: " + fps);
			secondCounter = 0.0f;
		}

		// update states
		stateManager.update(tpf);

		// simple update and root node
		simpleUpdate(tpf);
		rootNode.updateLogicalState(tpf);
		guiNode.updateLogicalState(tpf);
		rootNode.updateGeometricState();
		guiNode.updateGeometricState();

		// render states
		stateManager.render(renderManager);
		renderManager.render(tpf);
		simpleRender(renderManager);
		stateManager.postRender();
		
		if (igGuiOpen) {
			guiIGNode.setLocalTranslation(cam.getLocation().x, cam.getLocation().y, cam.getLocation().z - 1);
			guiIGNode.setLocalRotation(cam.getRotation());
		}
	}

	public void simpleUpdate(float tpf) {
	}

	public void simpleRender(RenderManager rm) {
	}

	public void simpleInitApp() {
		rootNode.attachChild(gameNode);	
		inMa = inputManager;
		//guiNode.detachAllChildren();
				
		terrainMap = new TerrainMap(assetManager, gameNode);
		
		/*NiftyJmeDisplay niftyDisplay = new NiftyJmeDisplay(assetManager, inputManager, audioRenderer, guiViewPort);
		mainGuiNifty = niftyDisplay.getNifty();
		mainGuiNifty.fromXml("interface/gui.xml", "start");
		
		// attach the nifty display to the gui view port as a processor
		guiViewPort.addProcessor(niftyDisplay);*/
		loadGame();
		
		//The HUD
		/*Picture pic = new Picture("HUD Picture");
		pic.setImage(assetManager, "texture/earth-side.png", true);
		pic.setWidth(settings.getWidth()/2);
		pic.setHeight(settings.getHeight()/2);
		pic.setPosition(settings.getWidth()/4, settings.getHeight()/4);
		guiHUDNode.attachChild(pic);*/
		
		BitmapText hudText = new BitmapText(guiFont, false);          
		hudText.setSize(guiFont.getCharSet().getRenderedSize());      // font size
		hudText.setColor(ColorRGBA.Blue);                             // font color
		hudText.setText("You can write any string here");             // the text
		hudText.setLocalTranslation(300, hudText.getLineHeight(), 0); // position
		guiHUDNode.attachChild(hudText);
		
		shootables = gameNode;
	}
	
	public static void loadGame() {
		boolean loaded = terrainMap.loadMap("map/map12/terrain.txt");
		if (loaded == true) {
			terrainMap.createMap();
		}
		//mainGuiNifty.exit();
		guiNode.attachChild(guiHUDNode);
	}
	
	public static void closeIGMenu() {
		igGuiNifty.exit();
		//myGuiViewPort.removeProcessor(igGuiDisplay);
		ownCam.setEnabled(true);
		igGuiOpen = false;
	}
}